#ifndef __YUECHUAN_CONFIG_H__
#define __YUECHUAN_CONFIG_H__

#include <memory>
#include <sstream>
#include <string>
#include <map>
#include <list>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <functional>
#include <boost/lexical_cast.hpp>
#include <yaml-cpp/yaml.h>
#include "log.h"
#include "thread.h"
#include "util.h"
namespace yuechuan {
    class Person {
    private:
        std::string m_name = "Make";
        int m_age = 0;
        bool m_sex = true;

    public:
        std::string toString() const {
            std::stringstream ss;
            std::string r_sex = m_sex ? "man" : "woman";
            ss << "[ Person name = " << m_name
               << " age = " << m_age
               << " sex = " << r_sex
               << " ] " << std::endl;
            return ss.str();
        }

        bool operator==(const Person &other) const {
            return this->m_age == other.getAge() && this->m_name == other.getName() && this->m_sex == other.getSex();
        }

        void setName(std::string name) { m_name = name; }

        void setAge(int age) { m_age = age; }

        void setSex(bool sex) { m_sex = sex; }

        std::string getName() const { return m_name; }

        int getAge() const { return m_age; }

        bool getSex() const { return m_sex; }
    };

    /**
     * @brief 配置基类
     * @details 把一些公用的属性定义
     */
    class ConfigVarBase {

    public:
        typedef std::shared_ptr<ConfigVarBase> ptr;

        /**
         * @brief 构造函数
         * @param name 配置名称
         * @param description 配置描述
         */
        ConfigVarBase(const std::string &name, const std::string &description = "")
                : m_name(name), m_description(description) {
            std::transform(m_name.begin(), m_name.end(), m_name.begin(), ::tolower);/// 配置中名称是无视大小写，全部转换为小写
        }

        /**
         * @brief 析构函数
         */
        virtual ~ConfigVarBase() {};

        /**
         * @brief 获取配置名称
         * @return std::string m_name
         */
        std::string getName() const { return m_name; }

        /**
         * @brief 获取配置描述
         * @return std::string m_description
         */
        std::string getDescription() const { return m_description; }

        /**
         * @brief 将配置信息转化为字符串
         * @details 方便写入
         * @return std::string
         */
        virtual std::string toString() = 0;

        /**
         * @brief 从字符串中解析配置信息
         * @param val 有配置信息的字符串
         * @return bool 是否是正确配置信息字符串格式
         */
        virtual bool fromString(const std::string &val) = 0;

        virtual std::string getTypeName() = 0;

    protected:
        std::string m_name;         /// 名称
        std::string m_description;  /// 描述
    };

    /**
     * @brief 通用的简单内置类型转换
     * @details 目的实现C++内置的简单数据类型相互转换 如 string <-> int string <-> float 等
     * @tparam F fromClass
     * @tparam T toClass
     */
    template<class F, class T>
    class LexicalCast {
    public:
        T operator()(const F &v) {
            return boost::lexical_cast<T>(v);
        }
    };

    /**
     * @brief 偏特化，从string类型转换为T类型的数组
     * @tparam T toClass 要转换的类型
     */
    template<class T>
    class LexicalCast<std::string, std::vector<T>> {
    public:
        std::vector<T> operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            typename std::vector<T> vec;
            std::stringstream ss;
            for (size_t i = 0; i < node.size(); ++i) {
                ss.str("");
                ss << node[i];
                vec.push_back(LexicalCast<std::string, T>()(ss.str()));
            }
            return vec;
        }
    };

    /**
     * @brief 偏特化，从F类型的数组转换为string类型
     * @tparam F  fromClass 被转换的类型
     */
    template<class F>
    class LexicalCast<std::vector<F>, std::string> {
    public:
        std::string operator()(const std::vector<F> &v) {
            YAML::Node node(YAML::NodeType::Sequence);

            std::stringstream ss;
            for (auto &i : v) {
                node.push_back(YAML::Load(LexicalCast<F, std::string>()(i)));
            }
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 偏特化，从string类型转换为T类型的列表
     * @tparam T toClass 要转换的类型
     */
    template<class T>
    class LexicalCast<std::string, std::list<T>> {
    public:
        std::list<T> operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            typename std::list<T> vec;
            std::stringstream ss;
            for (size_t i = 0; i < node.size(); ++i) {
                ss.str("");
                ss << node[i];
                vec.push_back(LexicalCast<std::string, T>()(ss.str()));
            }
            return vec;
        }
    };

    /**
     * @brief 偏特化，从F类型的列表转换为string类型
     * @tparam F  fromClass 被转换的类型
     */
    template<class F>
    class LexicalCast<std::list<F>, std::string> {
    public:
        std::string operator()(const std::list<F> &v) {
            YAML::Node node(YAML::NodeType::Sequence);
            std::stringstream ss;
            for (auto &i : v) {
                node.push_back(YAML::Load(LexicalCast<F, std::string>()(i)));
            }
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 偏特化，从string类型转换为T类型的集合
     * @tparam T toClass 要转换的类型
     */
    template<class T>
    class LexicalCast<std::string, std::set<T>> {
    public:
        std::set<T> operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            typename std::set<T> vec;
            std::stringstream ss;
            for (size_t i = 0; i < node.size(); ++i) {
                ss.str("");
                ss << node[i];
                vec.insert(LexicalCast<std::string, T>()(ss.str()));
            }
            return vec;
        }
    };

    /**
    * @brief 偏特化，从F类型的集合转换为string类型
    * @tparam F  fromClass 被转换的类型
    */
    template<class F>
    class LexicalCast<std::set<F>, std::string> {
    public:
        std::string operator()(const std::set<F> &v) {
            YAML::Node node(YAML::NodeType::Sequence);
            std::stringstream ss;
            for (auto &i : v) {
                node.push_back(YAML::Load(LexicalCast<F, std::string>()(i)));
            }
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 偏特化，从string类型转换为T类型的非排序集合
     * @tparam T toClass 要转换的类型
     */
    template<class T>
    class LexicalCast<std::string, std::unordered_set<T>> {
    public:
        std::unordered_set<T> operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            typename std::unordered_set<T> vec;
            std::stringstream ss;
            for (size_t i = 0; i < node.size(); ++i) {
                ss.str("");
                ss << node[i];
                vec.insert(LexicalCast<std::string, T>()(ss.str()));
            }
            return vec;
        }
    };

    /**
     * @brief 偏特化，从F类型的非排序集合转换为string类型
     * @tparam F  fromClass 被转换的类型
     */
    template<class F>
    class LexicalCast<std::unordered_set<F>, std::string> {
    public:
        std::string operator()(const std::unordered_set<F> &v) {
            YAML::Node node(YAML::NodeType::Sequence);

            std::stringstream ss;
            for (auto &i : v) {
                node.push_back(YAML::Load(LexicalCast<F, std::string>()(i)));
            }
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 偏特化，从string类型转换为T类型的字典
     * @tparam T toClass 要转换的类型
     */
    template<class T>
    class LexicalCast<std::string, std::map<std::string, T>> {
    public:
        std::map<std::string, T> operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            std::map<std::string, T> vec;
            std::stringstream ss;
            for (auto it = node.begin();
                 it != node.end(); ++it) {
                ss.str("");
                ss << it->second;
                vec.insert(std::make_pair(it->first.Scalar(), LexicalCast<std::string, T>()(ss.str())));
            }
            return vec;
        }
    };

    /**
     * @brief 偏特化，从F类型的字典转换为string类型
     * @tparam F  fromClass 被转换的类型
     */
    template<class F>
    class LexicalCast<std::map<std::string, F>, std::string> {
    public:
        std::string operator()(const std::map<std::string, F> &v) {
            YAML::Node node(YAML::NodeType::Map);
            for (auto &i : v) {
                node[i.first] = YAML::Load(LexicalCast<F, std::string>()(i.second));
            }
            std::stringstream ss;
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 偏特化，从string类型转换为T类型的非排序字典
     * @tparam T toClass 要转换的类型
     */
    template<class T>
    class LexicalCast<std::string, std::unordered_map<std::string, T>> {
    public:
        std::unordered_map<std::string, T> operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            std::unordered_map<std::string, T> vec;
            std::stringstream ss;
            for (auto it = node.begin();
                 it != node.end(); ++it) {
                ss.str("");
                ss << it->second;
                vec.insert(std::make_pair(it->first.Scalar(), LexicalCast<std::string, T>()(ss.str())));
            }
            return vec;
        }
    };

    /**
     * @brief 偏特化，从F类型的非排序字典转换为string类型
     * @tparam F  fromClass 被转换的类型
     */
    template<class F>
    class LexicalCast<std::unordered_map<std::string, F>, std::string> {
    public:
        std::string operator()(const std::unordered_map<std::string, F> &v) {
            std::stringstream ss;
            YAML::Node node(YAML::NodeType::Map);
            for (auto &i : v) {
                node[i.first] = YAML::Load(LexicalCast<F, std::string>()(i.second));
            }
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 自定义类型转换为string类型
     * @details boost内置的lexical_cast不能转换内置类型，所以要手动实现自定义类型的转化
     */
    template<>
    class LexicalCast<std::string, yuechuan::Person> {
    public:
        Person operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            Person p;
            p.setName(node["name"].as<std::string>());
            p.setAge(node["age"].as<int>());
            p.setSex(node["sex"].as<bool>());
            return p;
        }
    };

    /**
     * @brief string类型转换为自定义数据类型
     * @details boost内置的lexical_cast不支持内置类型转换，所以要手动实现自定义类型的转换
     */
    template<>
    class LexicalCast<yuechuan::Person, std::string> {
    public:
        std::string operator()(const Person &p) {
            YAML::Node node;
            node["name"] = p.getName();
            node["age"] = p.getAge();
            node["sex"] = p.getSex();
            std::stringstream ss;
            ss << node;
            return ss.str();
        }
    };

    /**
     * @brief 配置实现类
     * @tparam T 值的类型
     * @tparam FromStr
     * @tparam ToStr
     */
    template<class T, class FromStr = LexicalCast<std::string, T>, class ToStr = LexicalCast<T, std::string>>
    class ConfigVar : public ConfigVarBase {
    public:
        typedef RWMutex RWMutexType;
        typedef std::shared_ptr<ConfigVar> ptr;
        typedef std::function<void(const T &old_value, const T &new_value)> on_change_cb;    /// 对于配置文件发生改变触发的回调函数

        /**
         * @brief 构造函数
         * @param name 键的名称
         * @param default_value 默认值
         * @param description 描述
         */
        ConfigVar(const std::string &name, const T &default_value, const std::string &description = "")
                : ConfigVarBase(name, description),
                  m_val(default_value) {
        }
        /**
         * @brief 转换为字符串，继承
         * @return std::string
         */
        std::string toString() override {
            try {
                return ToStr()(m_val);
            }
            catch (const std::exception &e) {
                YUECHUAN_LOG_ERROR(YUECHUAN_LOG_ROOT()) << "ConfigVar::toString exception" << e.what() << " concert : "
                                                        << typeid(m_val).name() << "to string";
            }
            return "";
        }

        /**
         * @brief 从字符串中得到配置文件，一般是A.b的形式
         * @param val 要解析的字符串
         * @return bool 表示是否转换成功
         */
        bool fromString(const std::string &val) override {
            try {
                // m_val = boost::lexical_cast<T>(val);
                setValue(FromStr()(val));
            }
            catch (const std::exception &e) {
                YUECHUAN_LOG_ERROR(YUECHUAN_LOG_ROOT()) << "ConfigVar::toString exception" << e.what()
                                                        << "convert: string to " << typeid(m_val).name();
            }
            return false;
        }

        /**
         * @brief 获取当前配置项对应的value的值
         * @return T 对应的值是模板类T
         */
        const T getValue() const {
            RWMutexType::ReadLock lock(m_mutex);
            return m_val;
        }

        /**
         * @brief 设置当前配置项对应的value值
         * @details 当原来的值和新设置的值是一样时直接返回
         *          否则调用回调回调函数，将新值和旧值传入函数中
         *          最后再将新的值赋值给配置项
         * @param value  新的模板类对象值
         */
        void setValue(const T &value) {
            {// 产生局部域，当括号结束后，lock会调用其析构函数，方便下面加写锁
                RWMutexType::ReadLock lock(m_mutex);
                if (value == m_val) {
                    return;
                }

                for (auto &i : m_cbs) {
                    i.second(m_val, value);
                }
            }
            RWMutexType::WriteLock lock(m_mutex);
            m_val = value;
        }

        /**
         * @brief 获取当前配置中value对应的值的类型
         * @return
         */
        std::string getTypeName() override {
            RWMutexType::ReadLock lock(m_mutex);
            return typeid(T).name();
        }

        /**
         * @brief 配置修改事件监听函数
         * @param cb 修改事件的回调函数
         * @return
         */
        uint64_t addListener(const on_change_cb cb) {
            static uint64_t s_fun_id = 0;
            RWMutexType::WriteLock lock(m_mutex);
            ++s_fun_id;
            m_cbs[s_fun_id] = cb;
            return s_fun_id;
        }

        /**
         * @brief 删除函数
         * @details functional定义的函数是不支持比较的，所以不能放在set中，这样就不能将其删除了
         *          这次放在map中，通过键的形式找到对应的函数来将其删除
         * @param key uint64_t 要删除的函数对应的键的值，是一个唯一的值，一般使用hash
         */
        void delListener(const uint64_t key) {
            RWMutexType::WriteLock lock(m_mutex);
            m_cbs.erase(key);
        }

        /**
         * @brief 查找回调函数
         * @param key 回调函数对应的key的值
         * @return on_change_cb 回调函数 functional
         */
        on_change_cb getListener(const uint64_t key) {
            RWMutexType::ReadLock lock(m_mutex);
            auto it = m_cbs.find(key);
            return it == m_cbs.end() ? nullptr : it->second;
        }
        /**
         * @brief 清空回调函数
         */
        void clearListener() {
            RWMutexType::WriteLock lock(m_mutex);
            m_cbs.clear();
        }

    private:
        mutable RWMutexType m_mutex;            /// 读写锁
        T m_val;                                /// 值
        std::map<uint64_t, on_change_cb> m_cbs; /// 变更回调函数组
    };

    /**
     * @brief 配置管理类
     */
    class Config {
    public:
        typedef std::map<std::string, ConfigVarBase::ptr> ConfigVarMap;
        typedef RWMutex RWMutexType;

        /**
         * @brief 单例设计模式，创建一个Config对象
         * @tparam T
         * @param name key的名称
         * @param default_value value的默认值
         * @param description 配置描述
         * @return ConfigVar<T>::ptr 配置实现类的智能指针
         */
        template<class T>
        static typename ConfigVar<T>::ptr
        Lookup(const std::string &name, const T &default_value, const std::string &description = "") {

            auto it = GetDatas().find(name);
            if (it != GetDatas().end()) {
                auto tmp = std::dynamic_pointer_cast<LexicalCast<std::string, T>>(it->second);
                RWMutexType::WriteLock lock(GetMutex());
                if (tmp) {
                    YUECHUAN_LOG_INFO(YUECHUAN_LOG_ROOT()) << "Lookup name = " << name << " exists";
                } else {
                    YUECHUAN_LOG_ERROR(YUECHUAN_LOG_ROOT()) << " Lookup name = " << name << " exists but type not"
                                                            << typeid(T).name() << " real_type = "
                                                            << it->second->getTypeName();
                }
            }
            auto tmp = Lookup<T>(name);
            if (tmp) {
                YUECHUAN_LOG_INFO(YUECHUAN_LOG_ROOT()) << "Lookup name=" << name
                                                       << " exists";
                return tmp;
            }
            if (name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._0123456789") != std::string::npos) {
                YUECHUAN_LOG_ERROR(YUECHUAN_LOG_ROOT()) << "Lookup name invalid " << name;
                throw std::invalid_argument(name);
            }
            typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description));
            GetDatas()[name] = v;
            return v;
        }
        /**
         * @brief 查找配置，对于已经创建好的配置对象，传入配置中key的值来进行查找
         * @tparam T
         * @param name key的值
         * @return Config<T>::ptr 配置实现类的智能指针
         */
        template<class T>
        static typename ConfigVar<T>::ptr Lookup(const std::string &name) {
            RWMutexType::ReadLock lock(GetMutex());
            auto it = GetDatas().find(name);
            if (it == GetDatas().end()) {
                return nullptr;
            }
            return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);
        }
        /**
         * @brief 从yaml根节点中导入配置
         * @param root yaml文件的根节点
         */
        static void LoadFromYaml(const YAML::Node &root);

        /**
         * @brief 查找是否有与当前key值相同的项，有则返回
         * @param name 配置中的key的名称
         * @return ConfigVarBase::ptr or nullptr
         */
        static ConfigVarBase::ptr LookupBase(const std::string &name);

        static void Visit(std::function<void(ConfigVarBase::ptr)> cb);

    private:
        /**
         * @brief 静态方法来返回一个静态成员变量
         * @details 为了是解决静态成员变量初始化顺序问题
         *          如果直接使用 静态成员变量，在使用时直接访问这个成员变量，有可能该静态成员变量未被初始化
         *              这样在访问其中的变量及方法时就会报段错误
         *          如果使用静态函数，在函数中创建一个静态变量，然后再将该静态变量进行返回，这样就可以保证该静态变量在任何时候
         *              使用都是已经被创建好的
         * @return
         */
        static ConfigVarMap &GetDatas() {
            static ConfigVarMap s_datas;
            return s_datas;
        }

        static RWMutexType &GetMutex() {
            static RWMutexType s_mutex;
            return s_mutex;
        }
    };

} // namespace yuechuan

#endif
